/*
** OricSys.c
** Oric specific part of the disassembler.
*/

#include <windows.h>
#include <windowsx.h>
#include <memory.h>
#include <string.h>
#include <stdlib.h>
#include <io.h>
#include "..\compusys.h"

#define ORIC_FONT "Oric.FON"

#define END_OF_SYNC 0x24

HINSTANCE hDllInst;
char szDllPath[_MAX_PATH];
char szFontPath[_MAX_PATH];

/*
** allocate global memory
*/
static BYTE *MemoryAlloc(WORD wSize)
{
     return GlobalAllocPtr(GHND, (DWORD) wSize);
}

/*
** resize global memory
*/
static BYTE *MemoryRealloc(BYTE *lpBuf, WORD wSize)
{
     return GlobalReAllocPtr(lpBuf, (DWORD) wSize, GMEM_MOVEABLE);
}

/*
** free global memory
*/
static void MemoryFree(BYTE *lpBuf)
{
     GlobalFreePtr(lpBuf);
}

/*
** declare Oric font
*/
BOOL CALLBACK __export CompuInit(HINSTANCE hInst)
{
char *szSlash;

     /*
     ** Load font.
     */
     GetModuleFileName(hDllInst, szDllPath, sizeof(szDllPath));
     strcpy(szFontPath, szDllPath);
     if (szSlash = strrchr(szFontPath, '\\'))
          strcpy(szSlash + 1, ORIC_FONT);
     else strcpy(szFontPath, ORIC_FONT);
     if (! AddFontResource(szFontPath))
          return FALSE;

     /*
     ** if the font loaded successfully, notify other applications.
     */
     SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
     return TRUE;
}

/*
** remove Oric font.
*/
void CALLBACK __export CompuTerm(void)
{
     RemoveFontResource(szFontPath);
     SendMessage(HWND_BROADCAST, WM_FONTCHANGE, 0, 0);
}

/*
** retruns the menu item available
*/
WORD CALLBACK __export CompuGetMenu(void)
{
     return MENU_BINARY_FILE;
}

/*
** load a segment from a binary file
*/
BOOL CALLBACK __export CompuLoadSegment(int fd, SEGMENT *lpSeg, BOOL bReadType)
{
WORD wSize;

     /*
     ** get segment size.
     */
     wSize = lpSeg->wEnd - lpSeg->wBegin + 1;

     /*
     ** allocate memory for data and for byte type.
     */
     lpSeg->lpDump = MemoryAlloc(wSize);
     if (lpSeg->lpDump == NULL)
          return FALSE;
     lpSeg->lpType = MemoryAlloc(wSize);
     if (lpSeg->lpType == NULL)
          {
          MemoryFree(lpSeg->lpDump);
          lpSeg->lpDump = NULL;
          return FALSE;
          }

     /*
     ** read segment from file.
     */
     if ((WORD) read(fd, lpSeg->lpDump, wSize) != wSize)
          return FALSE;
     if (bReadType)
          if ((WORD) read(fd, lpSeg->lpType, wSize) != wSize)
               return FALSE;
     return TRUE;
}

/*
** send segment description to segment listbox.
*/
BOOL CALLBACK __export CompuUpdateSegment(HWND hSegmentList, SEGMENT *lpSeg)
{
char szBuf[80];
DWORD dwIndex;

     if (lpSeg->bBinary)
          wsprintf(szBuf, "$%04X-$%04X:%u \"%s\"", lpSeg->wBegin, lpSeg->wEnd, lpSeg->wEnd - lpSeg->wBegin + 1, lpSeg->szTitle);
     else wsprintf(szBuf, "$%04X-$%04X:BASIC \"%s\"", lpSeg->wBegin, lpSeg->wEnd, lpSeg->szTitle);
     dwIndex = SendMessage(hSegmentList, LB_ADDSTRING, 0, (LPARAM) (LPCSTR) szBuf);
     return (dwIndex != LB_ERR);
}

/*
** read an Atari binary file.
*/
BOOL CALLBACK __export CompuReadFile(HWND hSegmentList, int fd, SEGMENT Segment[], int nFirstSeg)
{
short iMagic;
DWORD dwFileLength;
WORD wBegin, wEnd;
WORD wSize;
char cAsm;
int nSeg;
char szBuf[8];
int nNameIndex;

     /*
     ** Check that the file begins with 2 0xFF.
     */
     if (read(fd, &iMagic, sizeof(iMagic)) != sizeof(iMagic))
          return FALSE;
     if (iMagic != 0x1616)
          return FALSE;
     dwFileLength = (DWORD) (filelength(fd) - sizeof(iMagic));

     /*
     ** read all segments
     */
     nSeg = nFirstSeg;
     while (dwFileLength)
          {

          /*
          ** read bytes until we find an end of synchronisation mark.
          */
          do   {
               if (read(fd, &cAsm, 1) != 1)
                    return TRUE;
               dwFileLength--;
               }
          while (cAsm != END_OF_SYNC);

          /*
          ** skip 2 bytes then read program type (Basic or 6502).
          */
          if (read(fd, szBuf, 2) != 2)
               return FALSE;
          if (read(fd, &cAsm, sizeof(cAsm)) != sizeof(cAsm))
               return FALSE;
          if (read(fd, szBuf, 1) != 1)
               return FALSE;
          dwFileLength -= 4;

          /*
          ** read segment start and end address.
          */
          if (read(fd, &wEnd, sizeof(wEnd)) != sizeof(wEnd))
               return FALSE;
          wEnd = ((wEnd << 8) & 0xFF00) + ((wEnd >> 8) & 0x00FF);
          if (read(fd, &wBegin, sizeof(wBegin)) != sizeof(wBegin))
               return FALSE;
          wBegin = ((wBegin << 8) & 0xFF00) + ((wBegin >> 8) & 0x00FF);
          if (wEnd < wBegin)
               return FALSE;
          dwFileLength -= sizeof(wBegin) + sizeof(wEnd);

          /*
          ** read name of program/data.
          */
          if (read(fd, szBuf, 1) != 1)
               return FALSE;
          dwFileLength--;
          for (nNameIndex = 0; nNameIndex < 16; nNameIndex++)
               {
               if (read(fd, &Segment[nSeg].szTitle[nNameIndex], 1) != 1)
                    return FALSE;
               dwFileLength--;
               if (Segment[nSeg].szTitle[nNameIndex] == 0)
                    break;
               }
          Segment[nSeg].szTitle[nNameIndex] = 0;

          /*
          ** check data size.
          */
          wSize = wEnd - wBegin + 1;
          if ((DWORD) wSize > dwFileLength)
               return FALSE;

          /*
          ** save segment type
          */
          Segment[nSeg].bBinary = (BOOL) cAsm;

          /*
          ** read segment data.
          */
          Segment[nSeg].wBegin = wBegin;
          Segment[nSeg].wEnd = wEnd;
          CompuLoadSegment(fd, &Segment[nSeg], FALSE);
          dwFileLength -= (DWORD) wSize;

          /*
          ** add this segment to the segment list.
          */
          if (CompuUpdateSegment(hSegmentList, &Segment[nSeg]) == FALSE)
               return FALSE;

          /*
          ** next segment.
          */
          nSeg++;
          if (nSeg >= MAX_SEGMENTS)
               return FALSE;
          }
     return TRUE;
}

/*
** Value of return.
*/
BYTE CALLBACK __export CompuGetReturn(void)
{
     return 0x0D;
}

/*
** DLL entry point
*/
BOOL CALLBACK LibMain(HINSTANCE hinst, UINT wDS, UINT cbHeap, DWORD unused)
{
     hDllInst = hinst;
     return TRUE;
}

/*
** DLL exit point
*/
int FAR PASCAL _WEP(int unused)
{
     return TRUE;
}
